{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "essential-mailing",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[0., 0., 0., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 1.,\n",
       "         0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.,\n",
       "         0., 1., 0., 0.],\n",
       "        [0., 0., 0., 1., 0., 0., 0., 0., 1., 1., 0., 0., 0., 0., 0., 1.,\n",
       "         0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.,\n",
       "         0., 1., 0., 0.],\n",
       "        [0., 0., 1., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 1.,\n",
       "         0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.,\n",
       "         0., 1., 0., 0.],\n",
       "        [0., 0., 0., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 1.,\n",
       "         0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.,\n",
       "         1., 1., 0., 0.],\n",
       "        [0., 0., 0., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 1.,\n",
       "         0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.,\n",
       "         1., 1., 1., 0.]]),\n",
       " array([[1, 0, 0],\n",
       "        [1, 0, 0],\n",
       "        [1, 0, 0],\n",
       "        [1, 0, 0],\n",
       "        [1, 0, 0]]))"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "\n",
    "#加载数据\n",
    "def load_data():\n",
    "    with open('数字123.txt') as fr:\n",
    "        lines = fr.readlines()\n",
    "\n",
    "    x = np.empty((len(lines), 36), dtype=float)\n",
    "    y = np.empty(len(lines), dtype=int)\n",
    "\n",
    "    for i in range(len(lines)):\n",
    "        line = lines[i].strip().split(',')\n",
    "        x[i] = line[:36]\n",
    "        y[i] = line[36]\n",
    "\n",
    "    #y变成one hot编码\n",
    "    y_one_hot = np.zeros((len(lines), 3), dtype=int)\n",
    "    y_one_hot[y == 1, 0] = 1\n",
    "    y_one_hot[y == 2, 1] = 1\n",
    "    y_one_hot[y == 3, 2] = 1\n",
    "\n",
    "    return x, y_one_hot\n",
    "\n",
    "\n",
    "x, y = load_data()\n",
    "x[:5], y[:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "communist-courage",
   "metadata": {},
   "outputs": [],
   "source": [
    "#常量\n",
    "N, M = x.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "ethical-seller",
   "metadata": {},
   "outputs": [],
   "source": [
    "#定义神经元对象\n",
    "class Neural:\n",
    "    def __init__(self, w, b):\n",
    "        self.w = w\n",
    "        self.b = b\n",
    "\n",
    "    def run(self, xi):\n",
    "        #线性计算\n",
    "        self.z = np.multiply(xi, self.w).sum() + self.b\n",
    "\n",
    "        #激活函数,sigmoid\n",
    "        self.a = 1 / (1 + np.exp(-self.z))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "wireless-genealogy",
   "metadata": {},
   "outputs": [],
   "source": [
    "#定义网络层对象\n",
    "class Layer:\n",
    "    def __init__(self, ns):\n",
    "        #神经元列表\n",
    "        self.ns = ns\n",
    "        self.out = np.empty((len(ns)))\n",
    "\n",
    "    #运行神经元,并记录运行结果\n",
    "    def run(self, xi):\n",
    "        for n in self.ns:\n",
    "            n.run(xi)\n",
    "\n",
    "        for i in range(len(self.ns)):\n",
    "            self.out[i] = self.ns[i].a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "compact-ensemble",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.70977385, 0.4577683 , 0.05793808, 0.64739933, 0.81131448,\n",
       "       0.82838851])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#定义第一层神经网络\n",
    "ns = []\n",
    "for i in range(6):\n",
    "    ns.append(Neural(np.random.randn(36), b=np.random.randn(1)[0]))\n",
    "layer_1 = Layer(ns)\n",
    "\n",
    "#运行第一层神经网络\n",
    "layer_1.run(x[0])\n",
    "\n",
    "layer_1.out"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "novel-israeli",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.36844697, 0.5742036 , 0.95180042])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#定义第二层神经网络\n",
    "ns = []\n",
    "for i in range(3):\n",
    "    ns.append(Neural(np.random.randn(6), b=np.random.randn(1)[0]))\n",
    "layer_2 = Layer(ns)\n",
    "\n",
    "#运行第二层神经网络\n",
    "layer_2.run(layer_1.out)\n",
    "\n",
    "layer_2.out"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "random-remove",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1.634493038926888, 120.85891829051137)"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#求loss\n",
    "def get_loss(x, y):\n",
    "    layer_1.run(x)\n",
    "    layer_2.run(layer_1.out)\n",
    "    return np.sum((layer_2.out - y)**2)\n",
    "\n",
    "\n",
    "def total_loss():\n",
    "    _sum = 0\n",
    "    for i in range(N):\n",
    "        _sum += get_loss(x[i], y[i])\n",
    "    return _sum\n",
    "\n",
    "\n",
    "get_loss(x[0], y[0]), total_loss()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "olive-surge",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([ 0.        ,  0.        ,  0.        , -0.03547165,  0.        ,\n",
       "         0.        ,  0.        ,  0.        ,  0.        , -0.03547165,\n",
       "         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,\n",
       "        -0.03547165,  0.        ,  0.        ,  0.        ,  0.        ,\n",
       "         0.        , -0.03547165,  0.        ,  0.        ,  0.        ,\n",
       "         0.        ,  0.        , -0.03547165,  0.        ,  0.        ,\n",
       "         0.        ,  0.        ,  0.        , -0.03547165,  0.        ,\n",
       "         0.        ]),\n",
       " -0.03547165121631224)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#我发明的暴力求梯度的方法.\n",
    "def get_gradient(n, x, y):\n",
    "    #这个变量就是增量了\n",
    "    upsilon = 1e-5\n",
    "\n",
    "    #先算出给增量前的loss\n",
    "    loss = get_loss(x, y)\n",
    "\n",
    "    #求w梯度\n",
    "    grad_w = np.empty(len(n.w))\n",
    "    for i in range(len(n.w)):\n",
    "        n.w[i] += upsilon\n",
    "        loss2 = get_loss(x, y)\n",
    "        n.w[i] -= upsilon\n",
    "        grad_w[i] = (loss2 - loss) / upsilon\n",
    "\n",
    "    #求b梯度\n",
    "    n.b += upsilon\n",
    "    loss2 = get_loss(x, y)\n",
    "    n.b -= upsilon\n",
    "    grad_b = (loss2 - loss) / upsilon\n",
    "\n",
    "    return grad_w, grad_b\n",
    "\n",
    "\n",
    "get_gradient(layer_1.ns[0], x[0], y[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "synthetic-sleeping",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 71.27809979054456\n",
      "1 55.53369600835406\n",
      "2 47.64408605359174\n",
      "3 39.200255958378676\n",
      "4 28.59178316767759\n",
      "5 19.637595883921538\n",
      "6 14.464849222522808\n",
      "7 11.336167390592282\n",
      "8 9.27956962809844\n",
      "9 7.834074941092935\n",
      "10 6.7625328504537086\n",
      "11 5.935215592660501\n",
      "12 5.275599989003669\n",
      "13 4.735778016691303\n",
      "14 4.284561791902418\n",
      "15 3.9010267865375927\n",
      "16 3.570711092743413\n",
      "17 3.283300228648476\n",
      "18 3.031197471849734\n",
      "19 2.808631234254595\n"
     ]
    }
   ],
   "source": [
    "#训练\n",
    "lr = 1e-1\n",
    "for epoch in range(20):\n",
    "    for i in range(len(layer_2.ns)):\n",
    "        n = layer_2.ns[i]\n",
    "        for j in range(N):\n",
    "            gred_w, gred_b = get_gradient(n, x[j], y[j])\n",
    "            n.w -= gred_w * lr\n",
    "            n.b -= gred_b * lr\n",
    "\n",
    "    for i in range(len(layer_1.ns)):\n",
    "        n = layer_1.ns[i]\n",
    "        for j in range(N):\n",
    "            gred_w, gred_b = get_gradient(n, x[j], y[j])\n",
    "            n.w -= gred_w * lr\n",
    "            n.b -= gred_b * lr\n",
    "\n",
    "    if epoch % 1 == 0:\n",
    "        print(epoch, total_loss())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "seven-drama",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.9895833333333334"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#测试\n",
    "correct = 0\n",
    "for i in range(N):\n",
    "    layer_1.run(x[i])\n",
    "    layer_2.run(layer_1.out)\n",
    "    if np.argmax(layer_2.out) == np.argmax(y[i]):\n",
    "        correct += 1\n",
    "\n",
    "correct / N"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
